package client.until;

import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;

/**
 * @author chengyadong
 * @date 2023/11/28 16:44
 * @description 远程调用实现类
 */
@Component
public class RestTemplateUtils {
	@Value("${security.oauth2.client-id}")
	private String clientId;
	@Value("${security.oauth2.client-secret}")
	private String clientSecret;
	@Value("${security.oauth2.authorization-grant-type}")
	private String authorizationGrantType;
	@Value("${security.oauth2.token-uri}")
	private String tokenUri;

	public static <T> JSONObject httpPostRequestForEntity(String url, T entity, String token) {
		try {
			RestTemplate restTemplate = new RestTemplate();
			HttpHeaders headers = new HttpHeaders();
			headers.set("Authorization", "Bearer " + token);
			HttpEntity<T> httpEntity = new HttpEntity<T>(entity, headers);
			List<HttpMessageConverter<?>> httpMessageConverters = restTemplate.getMessageConverters();
			httpMessageConverters.forEach(httpMessageConverter -> {
				if (httpMessageConverter instanceof StringHttpMessageConverter) {
					StringHttpMessageConverter messageConverter = (StringHttpMessageConverter) httpMessageConverter;
					messageConverter.setDefaultCharset(StandardCharsets.UTF_8);
				}
			});
			ResponseEntity<String> response = restTemplate.postForEntity(url, httpEntity, String.class);
			if (response.getStatusCodeValue() == 200)
				return JSONObject.parseObject(response.getBody());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public String getAccessToken(HttpServletRequest request) {
		HttpSession session = request.getSession();
		OAuth2AccessToken accessToken = (OAuth2AccessToken) session.getAttribute("access_token");
		//从session中获取当前客户端之前是否获取过token，如果为null，则调用授权服务器获取token
		if (accessToken == null) {
			accessToken = restTemplateAuthorization();
			session.setAttribute("access_token", accessToken);
		} else {
			//获取access_token的过期时间  默认有效时长2小时
			Instant expiresAt = accessToken.getExpiresAt();
			//判断是否过期
			boolean isExpired = Instant.now().isAfter(expiresAt);
			//如果已过期 则重新获取并更新session
			if (isExpired) {
				accessToken = restTemplateAuthorization();
				session.setAttribute("access_token", accessToken);
			}
		}
		//再次获取避免过期更新
		OAuth2AccessToken accessTokenResult = (OAuth2AccessToken) session.getAttribute("access_token");
		return accessTokenResult.getTokenValue();
	}

	//远程调用授权服务器获取accessToken  客户端模式只会生成access_token
	private OAuth2AccessToken restTemplateAuthorization() {
		//通过请求头的方式进行客户端的认证+获取access_token  也可以通过post请求方式进行认证（参数封装到请求体中）
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
		//:拼接，base64编码
		headers.setBasicAuth(clientId, clientSecret);
		//注意这里在初始化RestTemplate时，OAuth2AccessTokenResponseHttpMessageConverter是必须的，会对返回的结果进行类型转换，如果该对象，返回结果为null
		RestTemplate restTemplate = new RestTemplate(
				Arrays.asList(new FormHttpMessageConverter(), new OAuth2AccessTokenResponseHttpMessageConverter()));
		MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
		// 封装参数信息--模式类型
		parameters.add(OAuth2ParameterNames.GRANT_TYPE, authorizationGrantType);
		// 构建授权请求uri
		URI uri = UriComponentsBuilder
				.fromUriString(tokenUri)
				.build()
				.toUri();
		RequestEntity request = new RequestEntity(parameters, headers, HttpMethod.POST, uri);
		ResponseEntity<OAuth2AccessTokenResponse> response = restTemplate.exchange(request, OAuth2AccessTokenResponse.class);
		OAuth2AccessTokenResponse tokenResponse = response.getBody();
		return tokenResponse.getAccessToken();
	}
}
